/*
 * Copyright (c) 2024 Shenzhen Kaihong Digital Industry Development Co., Ltd.
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 * http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

#include "sle_host_hal.h"
#include "sle_host_hdi.h"
#include "sle_hilog.h"
#include "sle_loader_hal.h"
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
#include <time.h>

static SleHostHdiOpts* g_sleHostHalOpts = NULL;
static SleHostHdiCallbacks *g_sleHostHdiCbks = NULL;
static SleHostHalCallbacks *g_sleHostHalCbks = NULL;

static void OnSleHdiEnableCallback(SleHdiErrorCode errCode)
{
    SLE_LOGI("OnSleHdiEnableCallback errCode(0x%{public}08X)", errCode);
    if(g_sleHostHalCbks != NULL && g_sleHostHalCbks->OnHostHalEnableSleCb != NULL) {
        g_sleHostHalCbks->OnHostHalEnableSleCb(SleHalGetErrorCode(errCode));
    }
}

static void OnSleHdiDisableCallback(SleHdiErrorCode errCode)
{
    SLE_LOGI("OnSleHdiDisableCallback errCode(0x%{public}08X)", errCode);
    if(g_sleHostHalCbks != NULL && g_sleHostHalCbks->OnHosthalDisableSleCb != NULL) {
        g_sleHostHalCbks->OnHosthalDisableSleCb(SleHalGetErrorCode(errCode));
    }
}

SleHalErrorCode InitSleHostHal(void)
{
    SLE_LOGI("InitSleHostHal");
    SLE_ASSERT_AND_RETURN_RET_LOG(g_sleHostHalOpts == NULL, SLE_HAL_SUCCESS, "sleHostHal has been Inited");
    g_sleHostHalOpts = (SleHostHdiOpts*)malloc(sizeof(SleHostHdiOpts));
    SleHalErrorCode ret = SLE_HAL_ERR_UNKNOWN;
    ret = GetSleHostHalOpts(g_sleHostHalOpts);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "GetSleHostHalOpts fail(%{public}d)", ret);
    SLE_ASSERT_AND_RETURN_RET(g_sleHostHalOpts != NULL, SLE_HAL_ERR_COMMON);
    if (g_sleHostHdiCbks == NULL) {
        g_sleHostHdiCbks = (SleHostHdiCallbacks*)malloc(sizeof(SleHostHdiCallbacks));
        g_sleHostHdiCbks->OnSleEnabledCb = OnSleHdiEnableCallback;
        g_sleHostHdiCbks->OnSleDisabledCb = OnSleHdiDisableCallback;
        SLE_ASSERT_AND_RETURN_RET_LOG(g_sleHostHdiCbks != NULL, SLE_HAL_ERR_DRIVER_OR_SYSTEM, "SleHal or SleDriver has not been inited");
    }

    SleHdiErrorCode result = g_sleHostHalOpts->registerHostCbks(g_sleHostHdiCbks);
    ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "registerHostCbks fail(0x%{public}08X)", result);
    g_sleHostHalCbks = (SleHostHalCallbacks*)malloc(sizeof(SleHostHalCallbacks));

    return ret;
}

SleHalErrorCode DeinitSleHostHal(void)
{
    SLE_LOGI("HalDeinitSleHost");
    SLE_ASSERT_AND_RETURN_RET_LOG(g_sleHostHalOpts != NULL, SLE_HAL_SUCCESS, "sleHostHal has not been Inited");
    free(g_sleHostHalOpts);
    g_sleHostHalOpts = NULL;
    free(g_sleHostHdiCbks);
    g_sleHostHdiCbks = NULL;
    free(g_sleHostHalCbks);
    g_sleHostHalCbks = NULL;
    return SLE_HAL_SUCCESS;
}

SleHalErrorCode SleHostHalEnableSle(void)
{
    SLE_LOGI("SleHostHalEnableSle");
    SLE_ASSERT_AND_RETURN_RET(g_sleHostHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SleHdiErrorCode result = g_sleHostHalOpts->enableSle();
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "enableSle fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleHostHalDisableSle(void)
{
    SLE_LOGI("SleHostHalDisableSle");
    SLE_ASSERT_AND_RETURN_RET(g_sleHostHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SleHdiErrorCode result = g_sleHostHalOpts->disableSle();
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "disableSle fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleHostHalSetHostAddress(const SleDeviceAddress *hostAddr)
{
    SLE_LOGD("SleHostHalSetHostAddress");
    SLE_ASSERT_AND_RETURN_RET(g_sleHostHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(hostAddr != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleHostHalOpts->setHostAddress(hostAddr);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "setHostAddress fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleHostHalGetHostAddress(SleDeviceAddress *hostAddr)
{
    SLE_LOGD("SleHostHalGetHostAddress");
    SLE_ASSERT_AND_RETURN_RET(g_sleHostHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(hostAddr != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleHostHalOpts->getHostAddress(hostAddr);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "getHostAddress fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleHostHalSetHostName(const uint8_t *name, const uint8_t len)
{
    SLE_LOGD("SleHostHalSetHostName");
    SLE_ASSERT_AND_RETURN_RET(g_sleHostHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(name != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleHostHalOpts->setHostName(name, len);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "setHostName fail(0x%{public}08X)", result);
    return ret;
}

SleHalErrorCode SleHostHalGetHostName(uint8_t *name, uint8_t *len)
{
    SLE_LOGD("SleHostHalGetHostName");
    SLE_ASSERT_AND_RETURN_RET(g_sleHostHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(name != NULL && len != NULL, SLE_HAL_ERR_INVALID_PARAM);
    uint8_t hostName[SLE_DEVICE_NAME_LEN];
    uint8_t nameLen = SLE_DEVICE_NAME_LEN;
    SleHdiErrorCode result = g_sleHostHalOpts->getHostName(hostName, &nameLen);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    SLE_ASSERT_AND_RETURN_RET_LOG(ret == SLE_HAL_SUCCESS, ret, "getHostName fail(0x%{public}08X)", result);
    if(nameLen > *len) {
        SLE_LOGW("nameLen(%{public}d) > *len(%{public}d)", nameLen, *len);
        memcpy(name, hostName, *len);
    } else {
        memcpy(name, hostName, nameLen);
    }
    *len = nameLen;
    return ret;
}

SleHalErrorCode SleHostHalRegisterCallback(const SleHostHalCallbacks *halHostCallback)
{
    SLE_LOGI("SleHostHalRegisterCallback");
    SLE_ASSERT_AND_RETURN_RET(g_sleHostHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(halHostCallback != NULL, SLE_HAL_ERR_INVALID_PARAM);
    memcpy(g_sleHostHalCbks, halHostCallback, sizeof(SleHostHalCallbacks));
    return SLE_HAL_SUCCESS;
}

SleHalErrorCode SleHostHalUapiNvRead(uint16_t key, uint16_t kvalue_max_length, uint16_t *kvalue_length, uint8_t *kvalue)
{
    SLE_LOGD("SleHostHalUapiNvRead");
    SLE_ASSERT_AND_RETURN_RET(g_sleHostHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SLE_ASSERT_AND_RETURN_RET(kvalue_length != NULL, SLE_HAL_ERR_INVALID_PARAM);
    SleHdiErrorCode result = g_sleHostHalOpts->uapiNvRead(key, kvalue_max_length, kvalue_length, kvalue);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    return ret;
}

SleHalErrorCode SleHostHalUapiNvWrite(uint16_t key, uint8_t *kvalue, uint16_t kvalue_length)
{
    SLE_LOGD("SleHostHalUapiNvWrite");
    SLE_ASSERT_AND_RETURN_RET(g_sleHostHalOpts != NULL, SLE_HAL_ERR_NOT_READY);
    SleHdiErrorCode result = g_sleHostHalOpts->uapiNvWrite(key, kvalue, kvalue_length);
    SleHalErrorCode ret = SleHalGetErrorCode(result);
    return ret;
}